<?php

namespace App\Kuafu\User\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Base\Service\BaseService;
use App\Kuafu\Common\Service\OcrService;
use App\Kuafu\Config\Model\ConfigModel;
use App\Kuafu\Config\Service\ConfigService;
use App\Kuafu\Feishu\Model\FsUserModel;
use App\Kuafu\Log\Model\UserLoginLogModel;
use App\Kuafu\Mybank\Model\MybankEntryModel;
use App\Kuafu\Mybank\Service\MybankEntryService;
use App\Kuafu\Nsq\Enum\NsqCodeEnum;
use App\Kuafu\Pay\Channel\FuYou\FuYouBase;
use App\Kuafu\Shop\Exceptions\ShopException;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Model\ShopRecordsModel;
use App\Kuafu\Shop\Model\ShopStaffRecordLogModel;
use App\Kuafu\Shop\Model\ShopStaffRecordModel;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\Shop\Service\ShopStaffRecordLogService;
use App\Kuafu\Shop\Service\ShopStaffRecordService;
use App\Kuafu\Sms\Service\SmsService;
use App\Kuafu\Sys\Enum\SysCacheEnum;
use App\Kuafu\User\Enum\CodeEnum;
use App\Kuafu\User\Enum\RoleCodeEnum;
use App\Kuafu\User\Enum\UserCodeEnum;
use App\Kuafu\User\Enum\UserEnum;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\User\Model\Permissions;
use App\Kuafu\User\Model\Role;
use App\Kuafu\User\Model\RolePermissionMappings;
use App\Kuafu\User\Model\User;
use App\Kuafu\User\Model\UserDimissionEvaluateModel;
use App\Kuafu\User\Model\UserIdCardDetailModel;
use App\Kuafu\User\Model\UserRegistrationMappings;
use App\Kuafu\User\Model\UserRoleMapping;
use App\Remote\Tiger\OpenShop\OpenShopRemote;
use App\Scope\ShopScope;
use Carbon\Carbon;
use Darabonba\GatewaySpi\Models\InterceptorContext\request;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\HigherOrderBuilderProxy;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
use Kuafu\File\FileUtil;
use Kuafu\GeneralFs\BuildFs;
use Kuafu\IpWhite\Service\IpWhiteService;
use Kuafu\Nsq\NsqPublisher;
use Kuafu\Recognizer\RecognizeAllText;

class UserService extends BaseService
{
    protected static $codePrefix = "Kfzc:Mobile:";

    /**
     * 添加用户
     *
     * @param $request
     * @throws UserException
     */
    public static function addUser($request): int
    {
        $userId = self::addUserDB($request->header('brandId'), $request->username, $request->mobile,
            $request->password)->id;
        // 添加user role mapping
        UserRoleService::addUserRoleData($userId, $request->roles, $request->header('brandId'));

        return $userId;
    }

    /**
     * 仅添加user表的数据
     * @param int $brandId
     * @param string $username
     * @param string $mobile
     * @param string $password
     * @return User
     * @throws UserException
     */
    public static function addUserDB(int $brandId, string $username, string $mobile, string $password = '')
    {
        if (!$password) {
            $password = 1;
        }

        $user = new User();
        $salt = rand(1000, 9999);
        //正则匹配用户姓名
        self::pregMatchUserName($username);
        $user->brandId  = $brandId;
        $user->username = $username;
        $user->salt     = $salt;
        //正则匹配用户密码
        self::pregMatchPassword($password);
        $user->password  = bcrypt($password . $salt);
        $user->mobile    = $mobile;
        $user->createdAt = time();
        $user->updatedAt = time();
        $user->save();
        return $user;
    }

    public static function getUserInfo()
    {
        try {
            $authUser = AuthService::getAuthUser();
            $userInfo = $authUser->toArray();

            // 获取用户的角色归属

            if (empty($userInfo)) {
                throw new UserException(UserCodeEnum::ERR_USER_MOBILE_EXIST);
            }
            return $userInfo;
        } catch (\Exception $exception) {
            throw new UserException(UserCodeEnum::ERR_USER_MOBILE_EXIST, '', $exception);
        }
    }

    public static function getUserInfoById($id, $field = ["*"])
    {
        return User::getUserInfoById($id, $field);
    }

    public static function setUserInfo($userId, $userName, $mobile, $roles, $brandId)
    {
        self::pregMatchUserName($userName);
        self::pregMatchMobile($mobile);
        $rmsUserId = AuthService::getUserId(false);
        $data = [
            'username'     => $userName,
            'mobile'       => $mobile,
            'updatedByUid' => $rmsUserId,
            'updatedAt'    => time()
        ];

        // 通过userId获得用户拥有的门店列表
        $oldShopIds = ShopStaffRecordModel::query()
            ->where('userId', $userId)
            ->where('positionStatus', ShopStaffRecordModel::POSITION_STATUS_ON)
            ->pluck('shopId')
            ->toArray();
        $newShopIds = [];

        $historyAuditStatus = ShopStaffRecordService::getStaffHistoryAudit($userId);
        $auditStatus        = $historyAuditStatus['auditStatus'];
        $causeOfRejection   = $historyAuditStatus['causeOfRejection'];

        DB::beginTransaction();

        $user = User::query()->where(['id' => $userId])->first();
        $user->update($data);

        // 批量删除
        UserRoleService::deleteRoleData($userId);

        // 新增pos门店角色
        if (!empty($roles['shopRoles'])) {
            $newShopIds = array_merge($newShopIds, array_keys($roles['shopRoles']));
        }
        //新增商家app角色
        if (!empty($roles['merchantRoles'])) {
            $newShopIds = array_merge($newShopIds, array_keys($roles['merchantRoles']));
        }

        // 离职门店
        $leaveShopIds  = array_diff($oldShopIds, $newShopIds);
        $inShopShopIds = array_diff($newShopIds, $oldShopIds);
        ShopStaffRecordModel::query()
            ->where('userId', $userId)
            ->whereIn('shopId', $leaveShopIds)
            ->update([
                'positionStatus'   => ShopStaffRecordModel::POSITION_STATUS_OFF,
                'auditStatus'      => ShopStaffRecordModel::AUDIT_STATUS_LEAVE,
                'causeOfRejection' => '',
                'leaveTime'        => time(),
            ]);

        $shopCodes = Shop::query()
            ->whereIn('id', array_merge($leaveShopIds, $newShopIds))
            ->pluck('shopCode', 'id')
            ->toArray();

        // 添加日志
        foreach ($leaveShopIds as $leaveShopId) {
            // 操作日志
            ShopStaffRecordLogService::addRecord(
                $leaveShopId,
                $shopCodes[$leaveShopId] ?? 0,
                $userId,
                $rmsUserId,
                ShopStaffRecordLogModel::OPERATE_TYPE_BACK,
                ShopStaffRecordLogModel::ACTION_TYPE_LEAVE_ENTERPRISE,
                '-'
            );
        }

        // 添加关联关系
        foreach ($newShopIds as $newShopId) {
            $shopStaffRecordModel                 = ShopStaffRecordModel::query()
                ->updateOrCreate([
                    'shopId' => $newShopId,
                    'userId' => $userId
                ]);
            $shopStaffRecordModel->positionStatus = ShopStaffRecordModel::POSITION_STATUS_ON;
            $shopStaffRecordModel->shopCode       = $shopCodes[$newShopId] ?? 0;
            $shopStaffRecordModel->entryTime      = time();
            $shopStaffRecordModel->leaveTime      = 0;
            if (in_array($newShopId, $inShopShopIds)) {
                // 判断身份证健康证是否上传
                $idCardUploadRes = UserIdCardDetailModel::query()->where('userId', $userId)->exists();

                if (!$idCardUploadRes || $user->healthCardEndDate == 0) {
                    $auditStatus      = ShopStaffRecordModel::AUDIT_STATUS_EXPIRED_OR_LACK;
                    $causeOfRejection = '';
                }
                $shopStaffRecordModel->auditStatus      = $auditStatus;
                $shopStaffRecordModel->causeOfRejection = $causeOfRejection;
                $shopStaffRecordModel->createdByUid     = $rmsUserId;
                $shopStaffRecordModel->inShop           = ShopStaffRecordModel::IN_SHOP_ON;
            }
            $shopStaffRecordModel->updatedByUid     = $rmsUserId;
            $shopStaffRecordModel->save();

            if (in_array($newShopId, $inShopShopIds)) {
                // 操作日志
                ShopStaffRecordLogService::addRecord(
                    $newShopId,
                    $shopCodes[$newShopId] ?? 0,
                    $userId,
                    $rmsUserId,
                    ShopStaffRecordLogModel::OPERATE_TYPE_BACK,
                    ShopStaffRecordLogModel::ACTION_TYPE_JOIN_ENTERPRISE,
                    '-'
                );
            }
        }


        // 添加user role mapping
        UserRoleService::addUserRoleData($userId, $roles, $brandId);

        // 门店员工状态统计
        // Artisan::call('shop:refresh_shop_staff_statistics --userIds=' . $userId);

        DB::commit();

        Cache::forget(SysCacheEnum::getSysMenuList());

        // 发送用户修改消息
        self::pubUserChanges($user);
    }


    public static function deletedUser($uid): int
    {
        return User::query()->where(['id' => $uid])->update(['isDeleted' => 1]);
    }


    public static function setUserStatus($uid, $status)
    {
        $user = User::query()->where(['id' => $uid])->first();
        $user->update(['status' => $status]);

        // 发送用户修改消息
        self::pubUserChanges($user);

        return true;
    }

    public static function setUserMobile($mobile, $userId)
    {
        self::pregMatchMobile($mobile);
        //根据手机号查询用户是否存在
        $res = User::query()->where(['mobile' => $mobile])->where('id', '!=', $userId)->first();
        if ($res) {
            throw new UserException(UserCodeEnum::ERR_USER_MOBILE_EXIST);
        }
        self::setUserFieldByUserId($userId, ['mobile' => $mobile]);
    }

    /**
     * 修改用户密码
     * @param $userId
     * @param $password
     * @throws UserException
     */
    public static function setUserPassword($userId, $password)
    {
        self::pregMatchPassword($password);
        $salt     = rand(1000, 9999);
        $password = bcrypt($password . $salt);
        if (!$userId) {
            throw new UserException(UserCodeEnum::ERR_USER_NOT_EXIST);
        }
        //修改数据
        User::setUserInfoById($userId, ['password' => $password, 'salt' => $salt]);
    }

    public static function getUserValue($column, $value, $arr = [])
    {
        return User::getUserValue($column, $value, $arr);
    }

    public static function setUserFieldByUserId($userId, $arr)
    {
        try {
            $user = User::setUserInfoById($userId, $arr);
        } catch (\Exception $exception) {
            throw new UserException(UserCodeEnum::ERR_USER_UPDATE, '', $exception);
        }

        // 发送用户修改消息
        self::pubUserChanges($user);
    }

    public static function pregMatchUserName($userName)
    {
        if (!preg_match("/^[a-zA-Z0-9_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]+$/", $userName)) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME);
        }
    }

    public static function pregMatchPassword($pwd)
    {
        if (strlen($pwd) > 16 || strlen($pwd) < 8) {
            throw new UserException(UserCodeEnum::ERR_USER_PASSWORD_ONE);
        }
        if (preg_match("/^\d*$/", $pwd)) {
            throw new UserException(UserCodeEnum::ERR_USER_PASSWORD_TWO);
        }
        if (preg_match("/^[a-z]*$/i", $pwd)) {
            throw new UserException(UserCodeEnum::ERR_USER_PASSWORD_THREE);
        }
        if (!preg_match("/^[a-z\d]*$/i", $pwd)) {
            throw new UserException(UserCodeEnum::ERR_USER_PASSWORD_FOUR);
        }
    }

    public static function pregMatchMobile($mobile)
    {
        if (!preg_match("/^1[3456789]\d{9}$/", $mobile)) {
            throw new UserException(UserCodeEnum::ERR_USER_MOBILE);
        }
    }

    /**
     * 根据条件获取人
     *
     * @param int $lastId
     * @param int $type 1 店长 2 店长+店员
     * @return array
     */
    public static function getNotifyAllUserLists(int $lastId, int $type = 0, string $cityCode = '')
    {
        $userTable = (new User())->getTable();

        return UserRoleMapping::query()
                              ->select(['userId'])
                              ->rightJoin(
                                  $userTable . ' as user', 'user.id', '=',
                                  'user_role_mappings.userId',
                              )
                              ->where('type', RoleCodeEnum::ROLE_BUSINESS_TYPE)
                              ->where('userId', '>', $lastId)
                              ->where('user.status', '0')
                              ->where('user.isDeleted', '0')
                              ->when($type == RoleCodeEnum::ROLE_INTERNET_ROLE_MERCHANT, function ($query) {
                                  $roleId = config('merchant.manager_role_id');
                                  $query->where('roleId', $roleId);
                              })
                              ->when($cityCode != 'ALL', function ($query) use ($cityCode) {
                                  $cityCodeArr = explode(',', $cityCode);
                                  $shopIds     = Shop::query()
                                                     ->whereIn('city', $cityCodeArr)
                                                     ->select(['id'])
                                                     ->get()
                                                     ->pluck('id');
                                  $query->whereIn('shopId', $shopIds);
                              })
                              ->groupBy('userId')
                              ->orderBy('userId')
                              ->limit(1000)
                              ->get()
                              ->pluck('userId')
                              ->toArray();
    }

    /**
     * 获取用户列表
     *
     * @param $name
     * @param $status
     * @param $pageSize
     * @param $pageNum
     * @param int $brandId
     * @param string $mobile
     * @param int $roleId
     * @param int $shopId
     * @param string $url
     * @return array
     */
    public static function getUserList(
        $name,
        $status,
        $pageSize,
        $pageNum,
        int $brandId = 0,
        string $mobile = '',
        int $roleId = 0,
        int $shopId = 0,
        string $url = ""
    ): array {
        $userList = User::getUserDataPage($name, $status, $pageSize, $pageNum, $brandId, $mobile, $roleId, $shopId);
        // 获取员工 品牌,门店职位,适用门店

        if(!Str::contains($url, "openList")){
            $userIds       = array_column($userList->items(), 'id');
            $roleList      = UserRoleMapping::getRoleListByUserIds($userIds, $brandId);
            $userListItems = array_column($userList->items(), null, 'id');
            foreach ($userListItems as &$userData) {
                $userData['brandRoles'] = [];
                $userData['brandNums']  = 0;
                $userData['shopRoles']  = [];
                $userData['shopNums']   = 0;
            }
            foreach ($roleList as $roles) {
                if (key_exists($roles['userId'], $userListItems)) {
                    // 判断是web还是pos
                    switch ($roles['role_many_rel']['type'] ?? 0) {
                        case RoleCodeEnum::ROLE_WEB_TYPE:
                            $temp = $userListItems[$roles['userId']]['brandRoles'];
                            $num  = $userListItems[$roles['userId']]['brandNums'];
                            array_push($temp, $roles['roleName']);
                            $temp = array_unique($temp);
                            $num++;

                            $userListItems[$roles['userId']]['brandRoles'] = $temp;
                            $userListItems[$roles['userId']]['brandNums']  = $num;
                            break;
                        case RoleCodeEnum::ROLE_POS_TYPE:
                            $temp = $userListItems[$roles['userId']]['shopRoles'];
                            $num  = $userListItems[$roles['userId']]['shopNums'];
                            array_push($temp, $roles['roleName']);
                            $temp = array_unique($temp);
                            $num++;

                            $userListItems[$roles['userId']]['shopRoles'] = $temp;
                            $userListItems[$roles['userId']]['shopNums']  = $num;
                            break;
                        default:
                    }
                }
            }
        }

        return [
            'pageNum'  => $userList->currentPage(),
            'pageSize' => $userList->perPage(),
            'count'    => $userList->total(),
            'lists'    => $userList->items(),
        ];
    }

    /**
     * 添加员工信息
     * @param $username
     * @param $mobile
     * @param $status
     * @param $positions
     * @param $induction
     * @param $idCardFacePhoto
     * @param $idCardBackPhoto
     * @param $healthPhoto
     * @param $healthPhotoDate
     * @param $shopId
     * @param $brand
     * @return array
     * @throws UserException|GuzzleException
     */
    public static function addUserInfo(
        $username,
        $mobile,
        $inShop,
        $positions,
        $induction,
        $idCardFacePhoto,
        $idCardBackPhoto,
        $healthPhoto,
        $healthPhotoDate,
        $shopId,
        $brand,
        $rmsUserId
    )
    {
        // 兼容老版本
        if (is_numeric($induction) || $induction == null) {
            $induction = Carbon::createFromTimestamp($induction)->toDateString();
        }

        // 处理日期格式
        if (strlen((string)$healthPhotoDate)) {
            $healthPhotoDate = Carbon::parse(str_replace(['年', '月', '日', '.'], '', $healthPhotoDate))->toDateString();
        }

        if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON && Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->timestamp <= time()) {
            throw new UserException(UserCodeEnum::ERR_USER_HEALTH_CARD_END);
        }

        $shopModel = Shop::query()->where('id', $shopId)->first();
        $user      = User::query()->where('mobile', $mobile)->first();

        // 如果门店存在该手机号 禁止添加
        if ($user != null) {
            $isExistShop = UserRoleMapping::query()
                ->where('shopId', $shopId)
                ->where('userId', $user->id)
                ->exists();
            if ($isExistShop) {
                throw new UserException(UserCodeEnum::ERR_SHOP_USER_MOBILE_EXIST);
            }
        }

        $sendInitSms = false;
        $salt        = rand(1000, 9999);
        $password    = self::generatePassword(8);
        $external    = false;

        if (null == $user) {
            $user            = new User();
            $user->createdAt = time();
            // 发送短信(初始密码)
            $sendInitSms        = $sendNsq = true;
            $user->salt         = $salt;
            $user->password     = bcrypt($password . $salt);
            $user->createdByUid = $rmsUserId;
            // 入职时间-首次添加时间
            $user->inductionAt = Carbon::createFromFormat('Y-m-d', $induction)->timestamp;
        } else {
            // 内部禁止修改
            if ($inShop != null) {
                $external = self::prohibitModifyInternalEmployees($user, $username, $mobile);
            }
        }

        // 正则匹配用户姓名
        self::pregMatchUserName($username);
        $user->brandId      = $brand;
        $user->username     = $username;
        $user->mobile       = $mobile;
        $user->updatedAt    = time();
        $user->updatedByUid = $rmsUserId;

        if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {
            $user->healthCardPhoto   = ltrim(parse_url($healthPhoto, PHP_URL_PATH), '/');
            $user->healthCardEndDate = Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->endOfDay()->timestamp;
        }

        // 身份证名称
        $idCardName    = '';
        $idCardNumber  = '';
        $healthNumbers = [];

        try {
            if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {
                // 证件识别
                $faceInfo   = (new OcrService($idCardFacePhoto, 'url'))->idCardFaceOcr();
                $backInfo   = (new OcrService($idCardBackPhoto, 'url'))->idCardBackOcr();
                $healthInfo = self::healthCardOcr($healthPhoto);

                $idCardName    = $faceInfo['Name'];
                $idCardNumber  = $faceInfo['IDNumber'];
                $healthNumbers = $healthInfo['idCardNumbers'] ?? [];
            }
        } catch (\Exception $exception) {
            throw new UserException(UserCodeEnum::ERR_USER_ID_CARD_OCR);
        }

        if (strlen($idCardName) && !$external && $username != $idCardName) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME_EQUAL);
        }
        if (strlen($idCardName) && $external && strpos($username, $idCardName) === false) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME_EQUAL);
        }
        if (count($healthNumbers) && !in_array($idCardNumber, $healthNumbers)) {
            // throw new UserException(UserCodeEnum::ERR_USER_ID_CARD_EQUAL_HEALTH_CARD);
        }

        try {
            // 发送初始密码
            if ($sendInitSms) {
                Log::info("initPassword-添加新用户发送初始密码:" . $password);
                // 根据shopId 获得 shopName
                $shopName = (string)optional($shopModel)->name ?: '夸父炸串店';
                $shopName = str_replace(['(', ')', '（', '）', '【', '】', '-', ' '], '', $shopName);
                SmsService::userSignUpInitPassword($mobile, $shopName, $password);
            }

            $user->save();
            $userId = $user->id;

            $idCardStatus = ShopStaffRecordModel::ID_CARD_STATUS_LACK;

            // 添加身份证识别信息
            if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {
                // 身份证状态
                $idCardStatus = ShopStaffRecordModel::ID_CARD_STATUS_UPLOADED;

                $idCardModel               = UserIdCardDetailModel::query()
                    ->firstOrNew([
                        'userId' => $userId
                    ]);
                $idCardModel->facePhoto    = ltrim(parse_url($idCardFacePhoto, PHP_URL_PATH), '/');
                $idCardModel->backPhoto    = ltrim(parse_url($idCardBackPhoto, PHP_URL_PATH), '/');
                $idCardModel->name         = $faceInfo['Name'];
                $idCardModel->idCardNumber = $faceInfo['IDNumber'];
                $idCardModel->gender       = array_search($faceInfo['Gender'], UserIdCardDetailModel::GENDER_MAPPING);
                $idCardModel->birthDate    = $faceInfo['BirthDate'];
                $idCardModel->address      = $faceInfo['Address'];
                $idCardModel->nation       = $faceInfo['Nationality'];
                $idCardModel->office       = $backInfo['Issue'];
                $idCardModel->startDate    = Carbon::createFromFormat('Ymd', $backInfo['StartDate'])->timestamp;
                $idCardModel->endDate      = is_numeric($backInfo['EndDate']) ? Carbon::createFromFormat('Ymd', $backInfo['EndDate'])->timestamp : -1;
                $idCardModel->createdByUid = $rmsUserId;
                $idCardModel->updatedByUid = $rmsUserId;
                $idCardModel->createdAt    = time();
                $idCardModel->updatedAt    = time();
                $idCardModel->save();
            }

            // 门店员工信息处理
            $shopStaffRecordModel = ShopStaffRecordModel::query()
                ->updateOrCreate([
                    'shopId' => $shopId,
                    'userId' => $userId,
                ]);

            $shopStaffRecordModel->shopCode              = $shopModel->shopCode;
            $shopStaffRecordModel->inShop                = $inShop;
            $shopStaffRecordModel->idCardStatus          = ($inShop == ShopStaffRecordModel::IN_SHOP_ON ? $idCardStatus : ShopStaffRecordModel::ID_CARD_STATUS_DEFAULT);
            $shopStaffRecordModel->auditStatus           = ($inShop == ShopStaffRecordModel::IN_SHOP_ON ? ShopStaffRecordModel::AUDIT_STATUS_WAIT_AUDIT : ShopStaffRecordModel::AUDIT_STATUS_NOT_IN_SHOP);
            $shopStaffRecordModel->healthCardStatus      = ($inShop == ShopStaffRecordModel::IN_SHOP_ON ? ShopStaffRecordModel::HEALTH_CARD_STATUS_UPLOADED : ShopStaffRecordModel::HEALTH_CARD_STATUS_NULL);
            $shopStaffRecordModel->positionStatus        = ShopStaffRecordModel::POSITION_STATUS_ON;
            $shopStaffRecordModel->entryTime             = Carbon::createFromFormat('Y-m-d', $induction)->timestamp;
            $shopStaffRecordModel->leaveTime             = 0;
            $shopStaffRecordModel->lastManagerUpdateTime = time();
            $shopStaffRecordModel->createdByUid          = $rmsUserId;
            $shopStaffRecordModel->updatedByUid          = $rmsUserId;
            $shopStaffRecordModel->save();

            // 如果是到店 则审核状态全部变更为待审核
            if ($inShop == ShopStaffRecordModel::IN_SHOP_ON) {
                ShopStaffRecordModel::query()
                    ->where('userId', $userId)
                    ->where('positionStatus', ShopStaffRecordModel::POSITION_STATUS_ON)
                    ->where('inShop', ShopStaffRecordModel::IN_SHOP_ON)
                    ->update([
                         'auditStatus'      => ShopStaffRecordModel::AUDIT_STATUS_WAIT_AUDIT,
                         'causeOfRejection' => '',
                    ]);
            }

            // 添加日志
            ShopStaffRecordLogService::addRecord(
                $shopId,
                $shopModel->shopCode,
                $userId,
                $rmsUserId,
                ShopStaffRecordLogModel::OPERATE_TYPE_MERCHANT,
                ShopStaffRecordLogModel::ACTION_TYPE_JOIN_ENTERPRISE,
                '新建员工'
            );

            // 先删除
            UserRoleMapping::query()
                ->where('shopId', $shopId)
                ->whereIn('type', [RoleCodeEnum::ROLE_POS_TYPE, RoleCodeEnum::ROLE_BUSINESS_TYPE])
                ->withoutGlobalScope('isDel')
                ->where('userId', $userId)
                ->delete();
            // 添加user role mapping
            $position = array_unique(array_filter(explode(',', $positions)));
            $roles    = Role::getRoleListByIds($position);
            UserRoleService::addUserRoleMapData($userId, $shopId, $position, $brand, $roles, Carbon::createFromFormat('Y-m-d', $induction)->timestamp, (int)$inShop);
            $data = [
                'userId'  => $userId,
                'sendSms' => $sendInitSms
            ];
        } catch (\Exception $e) {
            throw new UserException(UserCodeEnum::ERR_USER_INSERT);
        }

        // 门店员工状态统计
        Artisan::call('shop:refresh_shop_staff_statistics --userIds=' . $userId . ' --updateTime=' . time());

        return $data;
    }

    /**
     * 设置员工信息
     * @param $userId
     * @param $username
     * @param $mobile
     * @param $inShop
     * @param $positions
     * @param $induction
     * @param $idCardFacePhoto
     * @param $idCardBackPhoto
     * @param $healthPhoto
     * @param $healthPhotoDate
     * @param $shopId
     * @param $brand
     * @return mixed
     * @throws GuzzleException
     * @throws UserException
     */
    public static function setStaffInfo(
        $userId,
        $username,
        $mobile,
        $inShop,
        $positions,
        $induction,
        $idCardFacePhoto,
        $idCardBackPhoto,
        $healthPhoto,
        $healthPhotoDate,
        $shopId,
        $brand,
        $rmsUserId,
        $status = 0
    ) {

        // 兼容老版本
        if (is_numeric($induction) || $induction == null) {
            $induction = Carbon::createFromTimestamp($induction)->toDateString();
        }

        // 处理日期格式
        if (strlen((string)$healthPhotoDate)) {
            $healthPhotoDate = Carbon::parse(str_replace(['年', '月', '日', '.'], '', $healthPhotoDate))->toDateString();
        }

        if ($status == CodeEnum::USER_STATUS_STOP) {
            self::oldVersionUserDimission($userId, $shopId);
            return $userId;
        }

        if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON && Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->timestamp <= time()) {
            throw new UserException(UserCodeEnum::ERR_USER_HEALTH_CARD_END);
        }

        $user      = User::find($userId);
        $shopModel = Shop::query()->where('id', $shopId)->first();

        if ($user == null || $shopModel == null) {
            throw new UserException(UserCodeEnum::ERR_USER_NOT_EXIST);
        }

        // 不能修改手机号
        if ($mobile != $user->mobile) {
            throw new UserException(UserCodeEnum::ERR_USER_NOT_EXIST);
        }

        // 内部禁止修改
        $external = false;
        if ($inShop != null) {
            $external = self::prohibitModifyInternalEmployees($user, $username, $mobile);
        }

        // 判断是否需要变更商家更新时间
        $recordChange = self::getUpdateStaffAuditStatus($userId, $shopId, $username, $inShop, $induction, $idCardFacePhoto, $idCardBackPhoto, $healthPhoto, $healthPhotoDate);

        self::pregMatchUserName($username);
        $user->username    = $username;

        // if ($status == CodeEnum::USER_STATUS_STOP) {
        //     UserRoleMapping::query()
        //         ->where('userId', $userId)
        //         ->where('shopId', $shopId)
        //         ->where('brandId', $brand)
        //         ->update([
        //             'isDeleted' => 1
        //         ]);
        //
        //     // 门店员工删除事件通知
        //     (new \Kuafu\Nsq\NsqPublisher(config('nsq.default.address')))
        //         ->pub(NsqCodeEnum::SHOP_STAFF_EVENT, [
        //             'userId'  => $userId,
        //             'shopId'  => $shopId,
        //             'isExist' => 1,// 退出
        //         ]);
        //     return 0;
        // } else {
        //     $user->status = $status;
        // }

        $user->mobile       = $mobile;
        $user->updatedAt    = time();
        $user->updatedByUid = $rmsUserId;

        if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {
            $user->healthCardPhoto     = ltrim(parse_url($healthPhoto, PHP_URL_PATH), '/');
            $user->healthCardEndDate   = Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->endOfDay()->timestamp;
        }

        // 身份证名称
        $idCardName    = '';
        $idCardNumber  = '';
        $healthNumbers = [];

        try {
            if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {
                // 证件识别
                $faceInfo   = (new OcrService($idCardFacePhoto, 'url'))->idCardFaceOcr();
                $backInfo   = (new OcrService($idCardBackPhoto, 'url'))->idCardBackOcr();
                $healthInfo = self::healthCardOcr($healthPhoto);

                $idCardName    = $faceInfo['Name'];
                $idCardNumber  = $faceInfo['IDNumber'];
                $healthNumbers = $healthInfo['idCardNumbers'] ?? [];
            }
        } catch (\Exception $exception) {
            throw new UserException(UserCodeEnum::ERR_USER_ID_CARD_OCR);
        }

        if (strlen($idCardName) && !$external && $username != $idCardName) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME_EQUAL);
        }

        if (strlen($idCardName) && $external && strpos($username, $idCardName) === false) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME_EQUAL);
        }

        if (count($healthNumbers) && !in_array($idCardNumber, $healthNumbers)) {
            // throw new UserException(UserCodeEnum::ERR_USER_ID_CARD_EQUAL_HEALTH_CARD);
        }

        // if ($password != null) {
        //     $salt       = rand(1000, 9999);
        //     $user->salt = $salt;
        //     //正则匹配用户密码
        //     self::pregMatchPassword($password);
        //     $user->password = bcrypt($password . $salt);
        // }

        // 如果是老板  默认添加店长权限
        try {
            $shopCode                = (int)Shop::query()->where('id', $shopId)->value('shopCode');
            $openShopSignOrderMobile = OpenShopRemote::getShopMobileByShopCode($shopCode)['mobile'] ?? '';
        } catch (\Exception $e) {
            $openShopSignOrderMobile = '';
        }

        // 如果是老板 默认添加店长权限
        if ($mobile == $openShopSignOrderMobile) {
            $positions .= ',' . config('merchant.manager_role_id');
        }

        // 身份证状态
        $idCardStatus = ShopStaffRecordModel::ID_CARD_STATUS_LACK;

        try {
            if ($inShop != null && $inShop == UserRoleMapping::IN_SHOP_ON) {

                $idCardStatus = ShopStaffRecordModel::ID_CARD_STATUS_UPLOADED;

                $idCardModel = UserIdCardDetailModel::query()
                    ->firstOrNew([
                        'userId' => $userId
                    ]);
                $idCardModel->facePhoto    = ltrim(parse_url($idCardFacePhoto, PHP_URL_PATH), '/');
                $idCardModel->backPhoto    = ltrim(parse_url($idCardBackPhoto, PHP_URL_PATH), '/');
                $idCardModel->name         = $faceInfo['Name'];
                $idCardModel->idCardNumber = $faceInfo['IDNumber'];
                $idCardModel->gender       = array_search($faceInfo['Gender'], UserIdCardDetailModel::GENDER_MAPPING);
                $idCardModel->birthDate    = $faceInfo['BirthDate'];
                $idCardModel->address      = $faceInfo['Address'];
                $idCardModel->nation       = $faceInfo['Nationality'];
                $idCardModel->office       = $backInfo['Issue'];
                $idCardModel->startDate    = Carbon::createFromFormat('Ymd', $backInfo['StartDate'])->timestamp;
                $idCardModel->endDate      = is_numeric($backInfo['EndDate']) ? Carbon::createFromFormat('Ymd', $backInfo['EndDate'])->timestamp : -1;
                $idCardModel->createdAt    = time();
                $idCardModel->updatedAt    = time();
                $idCardModel->save();
            }

            $user->save();

            // //获取员工角色（所有）
            // $staffAllRoles = UserRoleMapping::getStaffRoles($userId, $shopId, $brand);
            // //获取员工当前权限
            // $staffRoles = $staffAllRoles->where("isDeleted", "=", CodeEnum::APP_USER_NORMAL_ROLE)->pluck("roleId")
            //                             ->toArray();
            // //员工已删除权限
            // $isDelStaffRole = $staffAllRoles->where("isDeleted", "=", CodeEnum::APP_USER_DELETED_ROLE)->pluck("roleId")
            //                                 ->toArray();
            //
            // //查找员工已删除权限
            // $position    = array_unique(array_filter(explode(',', $positions)));
            // $upUserRole  = self::getNonExistentArray($position, $isDelStaffRole, 0);
            // $addUserRole = self::getNonExistentArray($position, $staffRoles, $isDelStaffRole);
            // $delUserRole = self::getNonExistentArray($staffRoles, $position, $isDelStaffRole);

            // 处理员工备案
            $shopStaffRecordModel = ShopStaffRecordModel::query()
                ->updateOrCreate([
                    'shopId' => $shopId,
                    'userId' => $userId,
                ]);

            if ($shopStaffRecordModel->positionStatus == ShopStaffRecordModel::POSITION_STATUS_OFF) {
                // 操作日志
                ShopStaffRecordLogService::addRecord(
                    $shopId,
                    $shopModel->shopCode,
                    $userId,
                    $rmsUserId,
                    ShopStaffRecordLogModel::OPERATE_TYPE_MERCHANT,
                    ShopStaffRecordLogModel::ACTION_TYPE_JOIN_ENTERPRISE,
                    '员工再入职'
                );
            } elseif ($recordChange !== false) {
                // 操作日志
                ShopStaffRecordLogService::addRecord(
                    $shopId,
                    $shopModel->shopCode,
                    $userId,
                    $rmsUserId,
                    ShopStaffRecordLogModel::OPERATE_TYPE_MERCHANT,
                    ShopStaffRecordLogModel::ACTION_TYPE_CHANGE_STAFF,
                    $recordChange
                );
            }

            // 获取审核状态
            $causeOfRejection = '';
            if ($inShop == ShopStaffRecordModel::IN_SHOP_OFF) {
                $auditStatus = ShopStaffRecordModel::AUDIT_STATUS_NOT_IN_SHOP;
            } elseif ($recordChange === false) {
                // 记录审核状态
                $historyAuditStatus = ShopStaffRecordService::getStaffHistoryAudit($userId);
                $auditStatus        = $historyAuditStatus['auditStatus'];
                $causeOfRejection   = $historyAuditStatus['causeOfRejection'];
            } else {
                $auditStatus = ShopStaffRecordModel::AUDIT_STATUS_WAIT_AUDIT;
            }

            $shopStaffRecordModel->shopCode              = $shopModel->shopCode;
            $shopStaffRecordModel->inShop                = $inShop;
            $shopStaffRecordModel->idCardStatus          = ($inShop == ShopStaffRecordModel::IN_SHOP_ON ? $idCardStatus : ShopStaffRecordModel::ID_CARD_STATUS_DEFAULT);
            $shopStaffRecordModel->auditStatus           = $auditStatus;
            $shopStaffRecordModel->causeOfRejection      = $causeOfRejection;
            $shopStaffRecordModel->healthCardStatus      = ($inShop == ShopStaffRecordModel::IN_SHOP_ON ? ShopStaffRecordModel::HEALTH_CARD_STATUS_UPLOADED : ShopStaffRecordModel::HEALTH_CARD_STATUS_NULL);
            $shopStaffRecordModel->positionStatus        = ShopStaffRecordModel::POSITION_STATUS_ON;
            $shopStaffRecordModel->entryTime             = Carbon::createFromFormat('Y-m-d', $induction)->timestamp;
            $shopStaffRecordModel->leaveTime             = 0;

            if ($recordChange !== false) {
                $shopStaffRecordModel->lastManagerUpdateTime = time();
            }

            $shopStaffRecordModel->createdByUid          = $rmsUserId;
            $shopStaffRecordModel->updatedByUid          = $rmsUserId;
            $shopStaffRecordModel->save();

            //删除员工角色信息
            UserRoleMapping::query()
                ->where('shopId', $shopId)
                ->whereIn('type', [RoleCodeEnum::ROLE_POS_TYPE, RoleCodeEnum::ROLE_BUSINESS_TYPE])
                ->withoutGlobalScope('isDel')
                ->where('userId', $userId)
                ->delete();
            // if (count($delUserRole)) {
            //     UserRoleService::setIsDelStaffData($userId, $shopId, $delUserRole, $brand,
            //         CodeEnum::APP_USER_DELETED_ROLE);
            // }

            // 添加user role mapping
            $positionArr = explode(',', $positions);
            $insertRoleMapping = [];
            Role::query()
                ->whereIn('id', $positionArr)
                ->get()
                ->map(function (Role $role) use (&$insertRoleMapping, $inShop, $induction, $userId, $brand, $shopId, $rmsUserId){
                    $insertRoleMapping[] = [
                        'userId'       => $userId,
                        'brandId'      => $brand,
                        'shopId'       => $shopId,
                        'entryTime'    => Carbon::createFromFormat('Y-m-d', $induction)->timestamp,
                        'inShop'       => (int)$inShop,
                        'roleId'       => $role->id,
                        'type'         => $role->type,
                        'createdByUid' => $rmsUserId,
                        'updatedByUid' => $rmsUserId,
                        'createdAt'    => time(),
                        'updatedAt'    => time(),
                    ];
                });
            UserRoleMapping::query()->insert($insertRoleMapping);

            // if (count(array_filter($addUserRole))) {
            //     //获取所有选中角色详细信息
            //     $roles = Role::getRoleListByIds($position);
            //     UserRoleService::addUserRoleMapData($userId, $shopId, $addUserRole, $brand, $roles, Carbon::createFromFormat('Y-m-d', $induction)->timestamp, $inShop);
            // }

            //更新员工权限
            // if (count($upUserRole)) {
            //     UserRoleService::setIsDelStaffData($userId, $shopId, $upUserRole, $brand,
            //         CodeEnum::APP_USER_NORMAL_ROLE, $inShop);
            // }
        } catch (\Exception $e) {
            throw new UserException(UserCodeEnum::ERR_USER_UPDATE);
        }

        // 门店员工状态统计
        Artisan::call('shop:refresh_shop_staff_statistics --userIds=' . $userId . ' --updateTime=' . ($recordChange !== false ? time() : 0) . ' --updateHealthCardEndDate=' . ($inShop == ShopStaffRecordModel::IN_SHOP_OFF ? 0 : ($recordChange !== false ? 1 : 0)));

        return $userId;
    }

    //获取Arr1中不存在的Arr2中并与Arr3关联的元素
    public static function getNonExistentArray($passive, $proactive, $practices)
    {
        $nonExistent = [];
        if ($practices != 0) {
            foreach ($passive as $item) {
                if (!in_array($item, $proactive) && !in_array($item, $practices)) {
                    $nonExistent[] = $item;
                }
            }
        } else {
            foreach ($passive as $item) {
                if (in_array($item, $proactive)) {
                    $nonExistent[] = (int)$item;
                }
            }
        }
        return $nonExistent;
    }

    /*
     * 获取给推送信息的可用用户
     */
    public static function getPushRemind(array $shopIds)
    {
        //TODO 写死~禁止修改
        $action     = 'app.user.createOrder';
        $permission = Permissions::query()
                                 ->where('action', $action)
                                 ->first();
        //获取对应的权限
        $roleIds = RolePermissionMappings::query()
                                         ->where('permissionId', $permission->id ?? 0)
                                         ->pluck('roleId')
                                         ->toArray();
        //获取对应的用户信息
        return UserRoleMapping::query()
                              ->with([
                                  'userRegistrationMappingRel' => function ($query) {
                                      $query->where('status', CodeEnum::USER_REGISTRATION_STATUS_ON);
                                  },
                                  'userRel',
                                  'shopRel'
                              ])
                              ->whereIn('shopId', $shopIds)
                              ->whereIn('roleId', $roleIds)
                              ->get()
                              ->map(function ($model) {
                                  return [
                                      'userId'         => $model->userId,
                                      'registrationId' => (string)optional($model->userRegistrationMappingRel)->registrationId,
                                      'phone'          => (string)optional($model->userRel)->mobile,
                                      'username'       => (string)optional($model->userRel)->username,
                                      'shopId'         => $model->shopId,
                                      'shopCode'       => (int)optional($model->shopRel)->shopCode,
                                      'shopName'       => (string)optional($model->shopRel)->name,
                                  ];
                              })->toArray();
    }

    public static function getUserInfoByIds($ids, array $fields = ['*'])
    {
        $idsArr = explode(',', $ids);
        return User::getUserInfoByIds($idsArr, $fields)->map(function ($user) {
            $user = $user->toArray();

            if (isset($user['avatar'])) {
                if (!strlen($user['avatar'])) {
                    $user['avatar'] = UserEnum::DEFAULT_AVATAR;
                }
                $user['avatar'] = FileUtil::domain() . '/' . $user['avatar'];
            }

            return $user;
        })->toArray();
    }

    public static function getWebUserList(string $username)
    {
        //获取所有web管理权限用户
        $webUserIds = UserRoleMapping::getWebUserIds();
        //查询用户信息
        //查询用户基本信息
        return User::query()
                   ->where('status', CodeEnum::USER_STATUS_USE)
                   ->when(strlen($username), function ($query) use ($username) {
                       $query->where("username", "like", "%{$username}%");
                   })
                   ->whereIn('id', $webUserIds)
                   ->get();
    }

    public static function getSiteTaskHandlerList(string $username)
    {
        //获取所有web管理权限用户
        $siteTaskHandlerIds = UserRoleMapping::getSiteTaskHandlerList();
        //查询用户信息
        //查询用户基本信息
        return User::query()
                   ->where('status', CodeEnum::USER_STATUS_USE)
                   ->when(strlen($username), function ($query) use ($username) {
                       $query->where("username", "like", "%{$username}%");
                   })
                   ->whereIn('id', $siteTaskHandlerIds)
                   ->get();
    }

    /**
     * 生成简单密码
     * @param int $length
     * @return string
     */
    public static function generateSimplePwd(int $length): string
    {
        $randStr = function (string $str) {
            return substr($str, mt_rand(0, strlen($str) - 1), 1);
        };

        $alphabet = 'abcdefghijklmnopqrstuvwxyz';
        $number   = '0123456789';

        $result = '';

        // 第一位固定字母
        $result .= $randStr($alphabet);

        // 第二位固定数字
        $result .= $randStr($number);

        for ($i = 0; $i < $length - 2; $i++) {
            $result .= $randStr($alphabet . $number);
        }

        return $result;
    }

    /**
     * 创建或恢复用户
     * @param int $brandId
     * @param int $mobile
     * @param string $name
     * @param string $pwd
     * @param array $roleList
     * @return array
     * @throws UserException
     */
    public static function createOrRestore(
        int $brandId,
        int $mobile,
        string $name,
        string $pwd = '',
        array $roleList = []
    ): array
    {
        try {
            $user = User::query()->withoutGlobalScope('isDel')->where('mobile', $mobile)->first();
            if (!$user) {

                // 检查名字 - 重复直接抛出异常
                $checkName = User::query()->withoutGlobalScope('isDel')->where('username', $name)->first();
                if ($checkName) {
                    throw new UserException(UserCodeEnum::ERR_USER_NAME_REPEAT);
                }

                // 新增
                $password = $pwd ?: self::generateSimplePwd(8);

                $user = self::addUserDB($brandId, $name, $mobile, $password);

                if ($roleList) {//创建用户角色
                    UserRoleService::addUserRoleData($user->id, $roleList, $brandId);
                }
                return [$user->id, $password];
            }

            // 更新
            if ($user->isDeleted) {
                $user->isDeleted = 0;
            }

            if ($user->status != CodeEnum::USER_STATUS_USE) {
                $user->status = CodeEnum::USER_STATUS_USE;
            }

            if ($pwd) {
                $user->password = bcrypt($pwd . $user->salt);
            }

            $user->save();

            // 发送用户修改消息
            self::pubUserChanges($user);

            return [$user->id, ''];
        } catch (\Exception $e) {
            throw new UserException(UserCodeEnum::ERR_USER_INSERT, $e->getMessage());
        }
    }

    public static function getShopOwnerCount()
    {
        $count = UserRoleMapping::query()
                                ->where('roleId', config('merchant.manager_role_id'))
                                ->join('users', 'user_role_mappings.userId', '=', 'users.id')
                                ->where('users.status', CodeEnum::USER_STATUS_USE)
                                ->count();
        return ['count' => $count];
    }

    /**
     * 判断用户是否为第一次登录
     * @param $request
     * @return bool
     * @throws UserException
     */
    public static function isFirstLogin($request)
    {
        $input = $request->only('username', 'password');
        $field = ['salt', 'status', 'id', 'username', 'mobile'];
        if (preg_match("/^1[3456789]\d{9}$/", $input['username'])) {
            $input['mobile'] = $input['username'];
            unset($input['username']);
            $userInfo = UserService::getUserValue('mobile', $input['mobile'], $field);
        } else {
            $userInfo = UserService::getUserValue('username', $input['username'], $field);
        }
        if (!$userInfo) {
            throw new UserException(UserCodeEnum::ERR_USER_NOT_EXIST);
        }
        if ($userInfo['status'] == CodeEnum::USER_STATUS_STOP) {
            throw new UserException(UserCodeEnum::ERR_USER_STATUS_STOP);
        }
        //判断日志
        $userLoginLogModel = UserLoginLogModel::query()
                                              ->where('userId', $userInfo->id)
                                              ->where('createdAt', '<', time() - UserLoginLogModel::LOGIN_FIRST_TIME)
                                              ->first();
        if ($userLoginLogModel == null) {
            return true;
        } else {
            return false;
        }
    }

    public static function getInfoByUserames(array $usernames): array
    {
        $users = User::query()->whereIn('username', $usernames)->get()->keyBy('username');

        return collect($usernames)->map(function ($username) use ($users) {
            return $users[$username] ?? null;
        })->toArray();
    }

    public static function getRegistrationIdByIds(array $ids)
    {
        $users = UserRegistrationMappings::query()
                                         ->whereIn('userId', $ids)
                                         ->where('status', CodeEnum::USER_REGISTRATION_STATUS_ON)
                                         ->select(['registrationId', 'userId'])
                                         ->get()
                                         ->keyBy('userId');

        $result = [];
        foreach ($users as $key => $user) {
            $result[$key] = $user['registrationId'];
        }

        return $result;
    }

    /**
     * @param int $shopId
     * @param bool $isStaff
     * @return array
     * @throws UserException
     * @throws BaseException
     * @throws ShopException
     * @throws GuzzleException
     */
    public static function getUserinfoWithShopAuth(int $shopId, bool $isStaff): array
    {
        $authUser = AuthService::getAuthUser();
        if ($authUser['status'] != 0) {
            throw new UserException(UserCodeEnum::ERR_USER_STATUS);
        }
        return [
            'id'        => $authUser['id'],
            'username'  => $authUser['username'],
            'mobile'    => $authUser['mobile'],
            'status'    => $authUser['status'],
            'avatar'    => FileUtil::domain() . '/' . (strlen($authUser['avatar']) ? $authUser['avatar'] : UserEnum::DEFAULT_AVATAR),
            'wechatId'  => $authUser['wechatId'],
            'address'   => ShopService::getShopInfo($shopId)['address'] ?? '',
            'createdAt' => $authUser['createdAt'],
            "shopLists" => ShopService::shopListDb($authUser['id'], $isStaff, "", $shopId) ?? [],
            "isStaff"   => $isStaff
        ];
    }

    /**
     * 获取用户角色
     *
     * @param object $params
     * @return array|void
     * @throws BaseException
     */
    public static function userRole(object $params)
    {
        try {
            $userRole = UserRoleMapping::query()->whereIn("userId", $params->userIds)
                                       ->where("shopId", $params->shopId)
                                       ->where("type", $params->type)
                                       ->where("brandId", $params->brandId)
                                       ->get()
                                       ->groupBy("userId")
                                       ->map(function ($v, $userId) {
                                           return ["userId" => $userId, "userRole" => $v->pluck("roleId")];
                                       })->values()->toArray();

            return [
                "userRole"     => $userRole,
                "platformRole" => Config::get("role")
            ];
        } catch (\Exception $exception) {
            handleException($exception, "获取用户角色失败");
        }
    }


    /**
     * 获取飞书用户
     *
     * @param object $params
     * @return array|void
     * @throws BaseException
     */
    public static function getFsUserByUserIds(object $params)
    {
        try {
            return [
                "fsUserList" => FsUserModel::query()
                                           ->whereIn("rmsUserId", $params->userIds)
                                           ->where("isExited", 0)
                                           ->get()
                                           ->toArray()
            ];
        } catch (\Exception $exception) {
            handleException($exception, "获取飞书用户信息失败");
        }
    }

    /**
     * 推送用户信息变更
     * @param User $user
     * @return bool
     * @throws \Exception
     */
    private static function pubUserChanges(User $user): bool
    {
        if (!$user) {
            return false;
        }

        $data['changes'] = collect($user->getChanges())->filter(function ($item, $key) {
            if (in_array($key, ['username', 'mobile', 'status'])) {
                return true;
            }

            return false;
        })->toArray();

        if (!$data['changes']) {
            return false;
        }

        $data['changes']['id'] = $user->id;

        return (new NsqPublisher(config('nsq.default.address')))
            ->pub(NsqCodeEnum::USER_BASE_INFO_EDIT, $data);
    }


    /**
     * 根据权限获得对应的用户列表
     * @param $roles
     * @return array
     */
    public static function getUserListByPower($roles): array
    {
        $roleArr = explode(',', $roles);
        return UserRoleMapping::query()
            ->with([
                'userRel' => function ($query) {
                    $query->where('status', \App\Kuafu\User\Enum\CodeEnum::USER_STATUS_USE);
                },
                'shopRel' => function ($query) {
                    $query->where('status', \App\Kuafu\Shop\Enum\CodeEnum::SHOP_STATUS_NORMAL);
                }
            ])
            ->whereIn('roleId', $roleArr)
            ->get()
            ->map(function (UserRoleMapping $mapping) {
                if ($mapping->shopRel == null || $mapping->userRel == null) {
                    return null;
                }
                //通过UserId获得是否开通支付
                $isOpenStatus = MybankEntryService::registerStatus($mapping->userId)['status'] ?? 0;
                if ($isOpenStatus == MybankEntryModel::STATUS_3) {
                    return null;
                }

                return [
                    'userId' => $mapping->userId,
                    'mobile' => $mapping->userRel->mobile,
                ];
            })->filter()->unique()->values()->toArray();
    }

    public static function getUsersByRoleName(string $roleName, int $type, int $shopId, ?int $isKf): array
    {
        $roleIds = Role::query()->where("name", 'like', "%{$roleName}%")->pluck("id")->toArray();
        if (!$roleIds) {
            return [];
        }

        $userIds = UserRoleMapping::query()
                              ->whereIn('roleId', $roleIds)
                              ->where('type', $type)
                              ->where('shopId', $shopId)
                              ->pluck('userId')
                              ->toArray();

        if (!$userIds) {
            return [];
        }

        // 内部人员
        $fsUserIds = FsUserModel::query()
                                ->whereIn('rmsUserId', $userIds)
                                ->where('isExited', 0)
                                ->pluck('rmsUserId')
                                ->toArray();

        return User::query()
                   ->whereIn('id', $userIds)
                   ->select('id', 'username')
                   ->get()
                   ->map(function ($user) use ($fsUserIds, $isKf) {

                       $item         = $user->toArray();
                       $item['isKf'] = in_array($user->id, $fsUserIds);

                       if ($isKf !== null) {
                           if ($item['isKf'] != $isKf) {
                              return null;
                           }
                       }

                       return $item;
                   })
                   ->filter()
                   ->toArray();
    }


    /**
     * 根据手机号查询用户名
     * @param int $userId
     * @param string $mobile
     * @return array
     * @throws UserException
     * @throws BaseException
     */
    public static function getUserInfoByMobile(int $userId, string $mobile): array
    {
        $key   = sprintf("getUserInfoByMobile:%d", $userId);
        $count = Redis::get($key);
        if ($count) {
            Redis::incr($key);
        } else {
            Redis::setex($key, getSwitchCacheTime(86400), 1);
        }
        $config = ConfigService::getConfigDetail("merchant", "getUserInfoByMobileLimit")["value"];
        if ($count > $config) {// 限制查询数据次数
            throw new UserException(UserCodeEnum::ERR_PMS_USER_NOT_SELECT);
        }
        if (!$mobile) {
            return [];
        }
        $field    = ['username', 'mobile'];
        $userInfo = UserService::getUserValue('mobile', $mobile, $field);
        if (!$userInfo) {
            return [];
        }
        return $userInfo->toArray();
    }


    /**
     * 获得上海未开通网商的用户ID
     * @param int $provinceCode
     * @return array
     */
    public static function getNoPowerWalletByProvince(int $provinceCode): array
    {
        // 获得已开通的用户
        $openPayUserIds = MybankEntryModel::query()
            ->pluck('userId')
            ->toArray();

        // 拥有订货权限或者是店长权限的展示钱包
        $roleManagerId = config('merchant.manager_role_id');

        // 获得已开通门店
        $openPayShopIds = UserRoleMapping::query()
            ->where('roleId', $roleManagerId)
            ->whereIn('userId', $openPayUserIds)
            ->pluck('shopId')
            ->toArray();


        $query = Shop::query()
            ->whereNotIn('id', $openPayShopIds)
            ->where('status', \App\Kuafu\Shop\Enum\CodeEnum::SHOP_STATUS_NORMAL)
            ->when($provinceCode, function ($queryBuilder) use ($provinceCode) {
                $queryBuilder->where('province', $provinceCode);
            })
            ->select('id');

        $bindings = $query->getBindings();

        $sql = $query->toSql();

        // SQL
        $sqlWithBindings = Str::replaceArray('?', $bindings, $sql);

        //$roleOrderId   = config('merchant.order_role_id');
        $userIds = UserRoleMapping::query()
            ->whereRaw("shopId in ({$sqlWithBindings})")
            ->with([
                'userRel' => function ($query) {
                    $query->where('status', \App\Kuafu\User\Enum\CodeEnum::USER_STATUS_USE);
                }
            ])
            ->where('roleId', $roleManagerId)
            ->pluck('userId')->unique()->values()->toArray();

        $webRoleUserId = UserRoleMapping::getWebUserIds();

        $filterUserIds = json_decode((string)optional(ConfigModel::getConfigByTypeKeyOne('myBank', 'filterUserIds'))->value, true);

        return array_values(array_diff($userIds, array_merge($webRoleUserId, $filterUserIds)));
    }


    /**
     * 获得商家APP登录的JWT
     * @param int $userId
     * @param string $userIp
     * @return array
     */
    public static function getMerchantLoginJwt(int $userId, string $userIp): array
    {
        $user = User::query()->where("id", $userId)->first();
        $jwt  = auth('api')
            ->setttl(CodeEnum::KEEP_LOGIN_TIME)
            ->claims([
                "type"           => UserCodeEnum::CODE_TEXT[UserCodeEnum::MERCHANT_TYPE],
                "ip"             => $userIp,
            ])->login($user);

        (new IpWhiteService($userId, UserCodeEnum::MERCHANT_TYPE, null))->login($userIp);

        return [
            'Authorization' => 'Bearer ' . $jwt,
        ];
    }

    /**
     * 模糊查询用户名称
     * @param string $username
     * @return array
     */
    public static function getRmsUserIdByUserName(string $username): array
    {
        return User::query()
                   ->where('status', CodeEnum::USER_STATUS_USE)
                   ->when(strlen($username), function ($query) use ($username) {
                       $query->where('username', 'like', "%{$username}%");
                   })
                   ->select(['id'])
                   ->get()
                   ->toArray();
    }


    /**
     * 健康证识别
     * @param string $file
     * @return array
     * @throws GuzzleException
     */
    public static function healthCardOcr(string $file): array
    {
        $res    = (new OcrService($file, 'url'))->allTextOcr();
        $string = implode("", $res);  // 将数组连接成一个字符串

        $patternDate = "/(\d{4}[-\/]\d{2}[-\/]\d{2})/";
        $patternIdCardNumber         = "/(\d{17}[\dXx])/";

        //dd($string);
        preg_match_all($patternIdCardNumber, $string, $matchesIdCardNumber);
        preg_match_all($patternDate, $string, $matchesDate);

        $idCardNumberArr = array_values(array_unique(Arr::collapse($matchesIdCardNumber)));
        $dateArr         = array_values(array_unique(Arr::collapse($matchesDate)));

        return [
            'date'          => empty($dateArr) ? '' : min($dateArr),
            'idCardNumber'  => empty($idCardNumberArr) ? '' : Arr::random($idCardNumberArr),
            'idCardNumbers' => $idCardNumberArr,
        ];

    }

    /**
     * 修改用户
     * @param int $shopId
     * @param int $userId
     * @param int $status
     * @param int $rmsUserId
     * @return void
     * @throws UserException|GuzzleException
     */
    public static function updateStatus(int $shopId, int $userId, int $status, int $rmsUserId)
    {
        // 通过shopId获得shopCode
        $shopModel = Shop::query()->where('id', $shopId)->first();
        $userModel = User::query()->where('id', $userId)->first();

        if ($shopModel == null || $userModel == null) {
            throw new UserException(UserCodeEnum::ERR_PMS_ID_NOT_EXIST);
        }

        try {
            $openShopSignOrderMobile = OpenShopRemote::getShopMobileByShopCode($shopModel->shopCode)['mobile'] ?? '';
        } catch (\Exception $e) {
            $openShopSignOrderMobile = '';
        }

        if ($status == CodeEnum::USER_STATUS_STOP && $userModel->mobile == $openShopSignOrderMobile) {
            throw new UserException(UserCodeEnum::ERR_SHOP_UPDATE_USER_ROLE);
        }

        DB::beginTransaction();
        try {
            // 离职员工
            ShopStaffRecordModel::query()
                ->where('userId', $userId)
                ->where('shopId', $shopId)
                ->update([
                    'positionStatus'        => $status,
                    'leaveTime'             => time(), // 离职时间
                    'updatedByUid'          => $rmsUserId,
                    'lastManagerUpdateTime' => time(),                                        // 商家更新时间
                    'auditStatus'           => ShopStaffRecordModel::AUDIT_STATUS_LEAVE,      // 审核状态
                    'causeOfRejection'      => '',                                            // 驳回原因
                    'healthCardStatus'      => ShopStaffRecordModel::HEALTH_CARD_STATUS_NULL, // 健康证状态
                ]);

            // 更新商家操作时间
            ShopRecordsModel::query()
                ->where('shopId', $shopId)
                ->update([
                    'lastManagerUpdateTime' => time(),
                ]);

            UserRoleMapping::query()
                ->where('userId', $userId)
                ->where('shopId', $shopId)
                ->whereIn('type', [RoleCodeEnum::ROLE_POS_TYPE, RoleCodeEnum::ROLE_BUSINESS_TYPE])
                ->withoutGlobalScope('isDel')
                ->update([
                    'isDeleted'    => $status,
                    'updatedByUid' => $rmsUserId,
                ]);

            if ($status == ShopStaffRecordModel::POSITION_STATUS_OFF) {
                // 员工离职操作日志
                ShopStaffRecordLogService::addRecord(
                    $shopId,
                    $shopModel->shopCode,
                    $userId,
                    $rmsUserId,
                    ShopStaffRecordLogModel::OPERATE_TYPE_MERCHANT,
                    ShopStaffRecordLogModel::ACTION_TYPE_LEAVE_ENTERPRISE,
                );

            }

            // 门店员工状态统计
            Artisan::call('shop:refresh_shop_staff_statistics --userIds=' . $userId);

        } catch (\Exception $exception) {
            DB::rollBack();
        }

        DB::commit();
    }

    /**
     * 生成密码
     */
    public static function generatePassword(int $length): string
    {
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $password = '';

        $characterCount = strlen($characters);
        for ($i = 0; $i < $length; $i++) {
            $randomIndex = mt_rand(0, $characterCount - 1);
            $password .= $characters[$randomIndex];
        }

        return $password;
    }

    /**
     * 禁止修改内部员工的手机号和姓名
     * 如果内部员工 则返回true 反之false
     */
    public static function prohibitModifyInternalEmployees($userModel, $username, $mobile): bool
    {
        // 判断是否是内部员工
        $countRoleByWeb = UserRoleMapping::query()
            ->where('userId', $userModel->id)
            ->where('type', RoleCodeEnum::ROLE_WEB_TYPE)
            ->count();

        if ($countRoleByWeb == 0) {
            return false;
        }

        $realName = FsUserModel::query()->where('rmsUserId', $userModel->id)->value('name') ?: $userModel->username;

        if (strpos($username, $realName) === false) {
            throw new UserException(UserCodeEnum::ERR_USER_NAME_EQUAL);
        }

        if ($mobile != $userModel->mobile) {
            throw new UserException(UserCodeEnum::ERR_MODIFY_INTERNAL_USER);
        }

        return true;
    }

    /**
     * 离职员工评价
     */
    public static function leaveEvaluate(int $score, int $userId, string $evaluateContent, int $shopId, int $rmsUserId)
    {
        // 添加评价
        $evaluateModel = new UserDimissionEvaluateModel();
        $evaluateModel->userId = $userId;
        $evaluateModel->shopId = $shopId;
        $evaluateModel->score = $score;
        $evaluateModel->evaluateContent = $evaluateContent;
        $evaluateModel->createdByUid = $rmsUserId;
        $evaluateModel->updatedByUid = $rmsUserId;
        $evaluateModel->createdAt = time();
        $evaluateModel->updatedAt = time();
        $evaluateModel->save();
    }


    /**
     * 处理老版本离职兼容问题
     */
    public static function oldVersionUserDimission(int $userId, int $shopId)
    {
        BuildFs::newRobot(0)
            ->setRobotConfig('https://open.feishu.cn/open-apis/bot/v2/hook/076e1730-3b71-4111-a5da-8309a1c7994f', 'tYpmtebCQ1YvzxqCi7pRFe')
            ->setTitleContent('操作员工离职', "用户ID:{$userId}\n门店ID:{$shopId}")
            ->send();

        // 直接删除员工门店绑定关系
        UserRoleMapping::query()
            ->where('userId', $userId)
            ->where('shopId', $shopId)
            ->whereIn('type', [RoleCodeEnum::ROLE_POS_TYPE, RoleCodeEnum::ROLE_BUSINESS_TYPE])
            ->delete();
    }

    /**
     * 在门店的所有用户列表
     * @param $shopId
     * @return array
     */
    public static function usersInShop($shopId): array
    {
        $userIds = UserRoleMapping::query()
                                  ->where('shopId', $shopId)
                                  ->where('type', RoleCodeEnum::ROLE_BUSINESS_TYPE)
//                                  ->where('inShop', UserRoleMapping::IN_SHOP_ON)
                                  ->where('leaveTime', 0)
                                  ->distinct()
                                  ->pluck('userId');
        if ($userIds->isEmpty()) {
            return [];
        }

        return User::query()->whereIn('id', $userIds)->get()->map(function ($user) {
            return [
                'id'     => $user->id,
                'username'   => $user->username,
            ];
        })->toArray();
    }

    /**
     * 在门店的所有用户列表
     * @param $shopIds
     * @return array
     */
    public static function usersInShops($shopIds): array
    {
        $filterUserIds = UserRoleMapping::getWebUserIds();

        $userMappings = UserRoleMapping::query()
                                       ->whereIn('shopId', $shopIds)
                                       ->where('type', RoleCodeEnum::ROLE_BUSINESS_TYPE)
                                       ->where('leaveTime', 0)
                                       ->get()
                                       ->filter(function ($item) use ($filterUserIds) {
                                           if (in_array($item->userId, $filterUserIds)) {
                                               return false;
                                           }
                                           return true;
                                       });
        $userIds      = $userMappings->pluck('userId')->unique()->values()->toArray();
        if (empty($userIds)) {
            return [];
        }
        $allUsers = User::query()->whereIn('id', $userIds)->get()->keyBy('id')->toArray();

        $format = [
            'roleConfig' => json_decode(
                ConfigModel::getConfigByTypeKeyOne("userRole", 'roleConfig')->value, true
            ),
            'list'       => []
        ];
        foreach ($userMappings as $mapping) {
            $shopId                                        = $mapping->shopId;
            $userId                                        = $mapping->userId;
            $format['list'][$shopId][$userId]['roleIds'][] = $mapping->roleId;
            $format['list'][$shopId][$userId]['userInfo']  = $allUsers[$userId] ?? [];
        }

        return $format;
    }


    /**
     * 获取健康证缺失的门店及店长ID列表
     */
    public static function getProblemShopStaffList(): array
    {
        // 店长 roleId
        $shopManagerRoleId = (int)config('merchant.manager_role_id');

        $data = [];

        $shopIds = ShopStaffRecordModel::query()
            ->where('inShop', ShopStaffRecordModel::IN_SHOP_ON)
            ->where('positionStatus', ShopStaffRecordModel::POSITION_STATUS_ON)
            ->whereIn('healthCardStatus', [ShopStaffRecordModel::HEALTH_CARD_STATUS_LACK, ShopStaffRecordModel::HEALTH_CARD_STATUS_ABOUT_TO_EXPIRE, ShopStaffRecordModel::HEALTH_CARD_STATUS_EXPIRED])
            ->pluck('shopId')
            ->toArray();

        if (empty($shopIds)) {
            return [];
        }

        $shopIds = Shop::query()
            ->where('status', \App\Kuafu\Shop\Enum\CodeEnum::SHOP_STATUS_NORMAL)
            ->whereIn('id', $shopIds)
            ->pluck('id')
            ->toArray();

        if (empty($shopIds)) {
            return [];
        }

        // 获得门店的店长ID
        UserRoleMapping::query()
            ->where('roleId', $shopManagerRoleId)
            ->whereIn("shopId", $shopIds)
            ->select(['shopId', 'userId'])
            ->chunk(1000, function ($userRoles) use (&$data){
                foreach ($userRoles as $userRole) {
                    $data[$userRole->shopId]['shopId'] = $userRole->shopId;
                    $data[$userRole->shopId]['userIds'][] = $userRole->userId;
                }
            });

        foreach ($data as $shopId => $shopItem) {
            $data[$shopId]['userIds'] = array_values(array_unique($shopItem['userIds']));
        }

        return array_values($data);
    }


    /**
     * 是否需要变更商家更新时间
     * @param $userId
     * @param $shopId
     * @param $username
     * @param $inShop
     * @param $induction
     * @param $idCardFacePhoto
     * @param $idCardBackPhoto
     * @param $healthPhoto
     * @param $healthPhotoDate
     * @return bool|string
     */
    public static function getUpdateStaffAuditStatus($userId, $shopId, $username, $inShop, $induction, $idCardFacePhoto, $idCardBackPhoto, $healthPhoto, $healthPhotoDate)
    {
        $oldStaffInfo = ShopStaffRecordModel::query()
            ->where('shopId', $shopId)
            ->where('userId', $userId)
            ->with(['userRel.userIdCardRel'])
            ->first();

        if ($oldStaffInfo == null) {
            return true;
        }

        try {
            if (
                $username == $oldStaffInfo->userRel->username &&
                $inShop == $oldStaffInfo->inShop &&
                $induction == Carbon::createFromTimestamp($oldStaffInfo->entryTime)->toDateString() &&
                strlen($healthPhotoDate) && Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->endOfDay()->timestamp == $oldStaffInfo->userRel->healthCardEndDate &&
                ltrim(parse_url($healthPhoto, PHP_URL_PATH), '/') == $oldStaffInfo->userRel->healthCardPhoto &&
                ltrim(parse_url($idCardFacePhoto, PHP_URL_PATH), '/') == $oldStaffInfo->userRel->userIdCardRel->facePhoto &&
                ltrim(parse_url($idCardBackPhoto, PHP_URL_PATH), '/') == $oldStaffInfo->userRel->userIdCardRel->backPhoto
            ) {
                return false;
            }
        } catch (\Exception $exception) {
            return true;
        }


        $changeItem = [];

        if ($username != $oldStaffInfo->userRel->username) {
            $changeItem[] = '姓名';
        }
        if ($inShop != $oldStaffInfo->inShop) {
            $changeItem[] = $inShop == ShopStaffRecordModel::IN_SHOP_ON ? '需到店' : '无需到店';
        }
        if ($induction != Carbon::createFromTimestamp($oldStaffInfo->entryTime)->toDateString()) {
            $changeItem[] = '入职时间';
        }
        if (strlen($healthPhotoDate) && Carbon::createFromFormat('Y-m-d', $healthPhotoDate)->addYear()->endOfDay()->timestamp != $oldStaffInfo->userRel->healthCardEndDate && $inShop == ShopStaffRecordModel::IN_SHOP_ON) {
            $changeItem[] = '健康证有效期';
        }
        if (ltrim(parse_url($healthPhoto, PHP_URL_PATH), '/') != $oldStaffInfo->userRel->healthCardPhoto && $inShop == ShopStaffRecordModel::IN_SHOP_ON) {
            $changeItem[] = '健康证';
        }
        if (ltrim(parse_url($idCardFacePhoto, PHP_URL_PATH), '/') != optional($oldStaffInfo->userRel->userIdCardRel)->facePhoto && $inShop == ShopStaffRecordModel::IN_SHOP_ON) {
            $changeItem[] = '身份证(正面)';
        }
        if (ltrim(parse_url($idCardBackPhoto, PHP_URL_PATH), '/') != optional($oldStaffInfo->userRel->userIdCardRel)->backPhoto && $inShop == ShopStaffRecordModel::IN_SHOP_ON) {
            $changeItem[] = '身份证(反面)';
        }

        return implode(',', $changeItem);
    }


    /**
     * 添加导入的员工信息
     * @param array $userList
     * @return array
     */
    public static function importSupplierCruiseStaff(array $userList): array
    {
        $data = [];
        foreach ($userList as $userInfo) {
            // 通过手机号获得用户信息
            if (isset($userInfo['mobile'])) {
                $userModel = User::query()
                    ->where('mobile', $userInfo['mobile'])
                    ->first();
            } elseif (isset($userInfo['id'])) {
                $userModel = User::query()
                    ->where('id', $userInfo['id'])
                    ->first();
            } else {
                $userModel = null;
            }

            $salt     = rand(1000, 9999);

            if ($userModel == null) {
                if (!strlen($userInfo['mobile'] ?? '')) {
                    continue;
                }

                if (isset($userInfo['password']) && strlen($userInfo['password']) > 8) {
                    $password = bcrypt($userInfo['password'] . $salt);
                } else {
                    $password = bcrypt(Str::random(8) . $salt);
                }

                // 新增用户
                $userModel = User::query()
                    ->create([
                        'mobile'    => $userInfo['mobile'],
                        'brandId'   => 1,
                        'password'  => $password,
                        'salt'      => $salt,
                        'username'  => $userInfo['username'] ?? ('User' . rand(1000, 9999)),
                        'createdAt' => time(),
                        'updatedAt' => time(),
                    ]);
            } else {
                if (isset($userInfo['username'])) {
                    $userModel->username = $userInfo['username'];
                }
                if (isset($userInfo['status'])) {
                    $userModel->status = $userInfo['status'];
                }
                $userModel->save();
            }

            $data[] = array_merge($userInfo, [
                'userId'   => $userModel->id,
                'username' => $userModel->username
            ]);
        }
        return $data;
    }
}
